﻿/*
* Usage examples:
public class Example : EventListener
{
	void Awake()
	{
		AddEventListener<GameObject>("prop collected", PropCollected);
		AddEventListener<float>("speed changed", SpeedChanged);
	}
	
	void PropCollected(GameObject _go)
	{
		// process gameObject
	}
	void SpeedChanged(float _speed)
	{
		// process speed
	}
}

...

Example _example = new Example();
_example.DispatchEvent<float>("speed changed", 0.5f );

...

 	   
*/

using UnityEngine;
using System;
using System.Collections.Generic;

public delegate void Callback();
public delegate void Callback<T>(T arg1);
public delegate void Callback<T, U>(T arg1, U arg2);
/*
public delegate void Callback<T, U, V>(T arg1, U arg2, V arg3);
*/

public class EventListener {
	
	#region MESSAGES
	static public BroadcastException CreateBroadcastSignatureException(string eventType) {
		return new BroadcastException(string.Format("Broadcasting message \"{0}\" but listeners have a different signature than the broadcaster.", eventType));
	}
	
	public class BroadcastException : Exception {
		public BroadcastException(string msg)
		: base(msg) {
		}
	}
	
	public class ListenerException : Exception {
		public ListenerException(string msg)
		: base(msg) {
		}
	}
	#endregion
	
	Dictionary<string, Delegate> eventTable = new Dictionary<string, Delegate>();
	
	#region PUBLIC METHODS
	public void AddEventListener(string eventType, Callback handler) 
	{
		if(eventTable.ContainsKey(eventType) )
		{
			eventTable[eventType] = (Callback)eventTable[eventType] + handler;
		}else{
			eventTable[eventType] = handler;
		}
	}
	
	public void AddEventListener<T>(string eventType, Callback<T> handler) 
	{
		if(eventTable.ContainsKey(eventType) )
		{
			eventTable[eventType] = (Callback<T>)eventTable[eventType] + handler;
		}else{
			eventTable[eventType] = handler;
		}
	}
	
	public void AddEventListener<T,U>(string eventType, Callback<T,U> handler) 
	{
		if(eventTable.ContainsKey(eventType) )
		{
			eventTable[eventType] = (Callback<T,U>)eventTable[eventType] + handler;
		}else{
			eventTable[eventType] = handler;
		}
		
	}
	
	public void RemoveEventListener(string eventType, Callback handler) 
	{
		if(eventTable.ContainsKey(eventType) )
		{
			eventTable[eventType] = (Callback)eventTable[eventType] - handler;
		}
	}
	
	public void RemoveEventListener<T>(string eventType, Callback<T> handler) 
	{
		if(eventTable.ContainsKey(eventType) )
		{
			eventTable[eventType] = (Callback<T>)eventTable[eventType] - handler;
		}
	}
	
	public void RemoveEventListener<T,U>(string eventType, Callback<T,U> handler) 
	{
		if(eventTable.ContainsKey(eventType) )
		{
			eventTable[eventType] = (Callback<T,U>)eventTable[eventType] - handler;
		}
	}
	
	public void DispatchEvent(string eventType)
	{
		Delegate d;
		if (eventTable.TryGetValue(eventType, out d)) {
			Callback callback = d as Callback;
			
			if (callback != null) {
				callback();
			} else {
				throw CreateBroadcastSignatureException(eventType);
			}
		}else{
			Debug.LogWarning("no se pudo con: " + eventType);
		}
	}
	
	public int count
	{	
		get{ return eventTable.Count; }
	}
	
	public void DispatchEvent<T>(string eventType, T _arg1)
	{
		Delegate d;
		if (eventTable.TryGetValue(eventType, out d)) {
			Callback<T> callback = d as Callback<T>;
			
			if (callback != null) {
				callback(_arg1);
			} else {
				throw CreateBroadcastSignatureException(eventType);
			}
			
		}else{
			Debug.LogWarning("no se pudo con: " + eventType);
		}
	}
	
	public void DispatchEvent<T,U>(string eventType, T _arg1, U _arg2)
	{
		Delegate d;
		if (eventTable.TryGetValue(eventType, out d)) {
			Callback<T,U> callback = d as Callback<T,U>;
			
			if (callback != null) {
				callback(_arg1, _arg2);
			} else {
				throw CreateBroadcastSignatureException(eventType);
			}
			
		}else{
			Debug.LogWarning("no se pudo con: " + eventType);
		}
	}
	
	public void Clear()
	{
		eventTable.Clear();
	}
	#endregion
}
